﻿#include "FITKAcousticsVTKGraphObjectMergedData.h"
#include "FITKAcousticsVTKGraphActor.h"

// VTK
#include <vtkProperty.h>
#include <vtkPoints.h>
#include <vtkMultiBlockDataSet.h>
#include <vtkCompositeDataGeometryFilter.h>
#include <vtkMapper.h>
#include <vtkCellData.h>
#include <vtkExtractBlock.h>

// App
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"

// Graph and filter
#include "FITKAcousticsVTKCommons.h"
#include "FITKAcousticsVTKSharedDataManager.h"
#include "FITKAcousticsVTKGraphObjectSEASelectMergedData.h"
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor.h"

namespace Exchange
{
    FITKAcousticsVTKGraphObjectMergedData::FITKAcousticsVTKGraphObjectMergedData(Core::FITKAbstractDataObject* dataObj)
        : FITKAcousticsVTKGraphObject3DPost(dataObj)
    {
        // Set the layer need to be rendered.
        setRenderLayer(0, 2);
    }

    FITKAcousticsVTKGraphObjectMergedData::~FITKAcousticsVTKGraphObjectMergedData()
    {
        // Delete vtk objects.
        deleteVtkObj(m_multiBlockDataSet);
        deleteVtkObj(m_extractBlock);
        deleteVtkObj(m_comp2Poly);
    }

    void FITKAcousticsVTKGraphObjectMergedData::init()
    {
        // Create the filter.
        m_multiBlockDataSet = vtkMultiBlockDataSet::New();

        m_extractBlock = vtkExtractBlock::New();
        m_extractBlock->SetInputData(m_multiBlockDataSet);

        m_comp2Poly = vtkCompositeDataGeometryFilter::New();
        m_comp2Poly->SetInputConnection(m_extractBlock->GetOutputPort());

        // Create the highlightor.
        m_highlightSelector = new FITKAcousticsVTKGraphObjectSEASelectMergedData;
        m_addinGraphObjList.push_back(m_highlightSelector);
    }

    void FITKAcousticsVTKGraphObjectMergedData::update(bool forceUpdate)
    {
        Q_UNUSED(forceUpdate);

        // Update the visibility only.
        updateVisibility();
    }

    void FITKAcousticsVTKGraphObjectMergedData::updateVisibility()
    {
        // Update the visibility with the flags.
        //@{
        // Show or hide actors.
        setVisible(getDataVisibility());
        //@}
    }

    void FITKAcousticsVTKGraphObjectMergedData::updateById(int dataId, bool forceUpdate)
    {
        Q_UNUSED(dataId);
        Q_UNUSED(forceUpdate);
    }

    void FITKAcousticsVTKGraphObjectMergedData::updateByIds(QList<int> dataIds, bool forceUpdate)
    {
        for (const int & dataId : dataIds)
        {
            updateById(dataId, forceUpdate);
        }
    }

    void FITKAcousticsVTKGraphObjectMergedData::highlight(FITKAcousticsVTKCommons::ShapeType type, QColor color)
    {
        // Save the highlight flag.
        FITKAcousticsVTKGraphObject3D::highlight(type, color);
    }

    void FITKAcousticsVTKGraphObjectMergedData::disHighlight()
    {
        // Save the highlight flag.
        FITKAcousticsVTKGraphObject3D::disHighlight();
    }

    void FITKAcousticsVTKGraphObjectMergedData::advanceHighlight(FITKAcousticsVTKCommons::ShapeType type, QVector<int> indice, QColor color)
    {
        if (m_highlightSelector)
        {
            for (const int & id : indice)
            {
                m_highlightSelector->addSelectData(id);
            }
            
            m_highlightSelector->setColor(color);
        }

        // Save the highlight flag.
        FITKAcousticsVTKGraphObject3D::advanceHighlight(type, indice, color);
    }

    void FITKAcousticsVTKGraphObjectMergedData::disAdvanceHighlight()
    {
        if (m_highlightSelector)
        {
            m_highlightSelector->clearData();
        }

        // Save the highlight flag.
        FITKAcousticsVTKGraphObject3D::disAdvanceHighlight();
    }

    void FITKAcousticsVTKGraphObjectMergedData::setPickMode(FITKAcousticsVTKCommons::ShapePickMode mode)
    {
        bool pickable = false;

        switch (mode)
        {
        case Exchange::FITKAcousticsVTKCommons::PickAll:
            pickable = true;
            break;
        case Exchange::FITKAcousticsVTKCommons::PickNone:
        case Exchange::FITKAcousticsVTKCommons::PickVertex:
        case Exchange::FITKAcousticsVTKCommons::PickEdge:
        case Exchange::FITKAcousticsVTKCommons::PickFace:
        case Exchange::FITKAcousticsVTKCommons::PickSolid:
        case Exchange::FITKAcousticsVTKCommons::PickNode:
        case Exchange::FITKAcousticsVTKCommons::PickElement:     
        default:
            pickable = false;
            break;
        }

        // Update all actors.
        for (vtkProp* prop : m_actorList)
        {
            if (prop)
            {
                prop->SetPickable(pickable);
            }
        }
    }

    int FITKAcousticsVTKGraphObjectMergedData::getShapeIdByVTKCellId(int vtkId, FITKAcousticsVTKCommons::ShapeMeshAbsEnum topAbsShapeType)
    {
        Q_UNUSED(topAbsShapeType);

        if (!m_fActor)
        {
            return -1;
        }

        // Get the input dataset.
        vtkMapper* mapper = m_fActor->GetMapper();
        if (!mapper)
        {
            return -1;
        }

        vtkDataSet* dataSet = mapper->GetInputAsDataSet();
        if (!dataSet)
        {
            return -1;
        }

        vtkCellData* cellData = dataSet->GetCellData();
        if (!cellData)
        {
            return -1;
        }

        // Get the id array.
        vtkIntArray* idArray = vtkIntArray::SafeDownCast(cellData->GetArray(DATA_ID_ARRAY_NAME));
        if (!idArray)
        {
            return -1;
        }

        int nVal = idArray->GetNumberOfValues();
        if (vtkId >= nVal)
        {
            return -1;
        }

        int dataId = idArray->GetValue(vtkId);

        return dataId;
    }

    void FITKAcousticsVTKGraphObjectMergedData::generateGraph()
    {
        // Create grid actor.
        m_fActor = FITKAcousticsVTKGraphActor::New();
        m_fActor->setGraphObject(this);
        m_fActor->SetPickable(false);
        m_fActor->SetVisibility(true);
        m_fActor->GetProperty()->SetRepresentation(2);
        m_fActor->GetProperty()->SetPointSize(0.);
        m_fActor->GetProperty()->SetLineWidth(1.);
        m_fActor->GetProperty()->SetEdgeVisibility(false);
        m_fActor->setRelativeCoincidentTopologyPolygonOffsetParameters(m_polygonOffset);
        addActor(m_fActor);

        // Set the input connection.
        m_fActor->setInputConnection(m_comp2Poly->GetOutputPort());
    }
}   // namespace Exchange